package com.emax.zhenghe.omsbase.modules.bill.controller;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.auth.api.dto.EntAgreementResponseDTO;
import com.auth.api.service.EnterpriseAgreementService;
import com.auth.api.vo.EnterpriseAgreementVo;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.emax.common.DubboApps;
import com.emax.etl.rpcapi.datacenter.SysDownloadRecordService;
import com.emax.etl.rpcapi.model.SysDownloadRecordDTO;
import com.emax.zhenghe.common.api.vo.MyIPage;
import com.emax.zhenghe.common.api.vo.Result;
import com.emax.zhenghe.common.api.vo.ResultX;
import com.emax.zhenghe.common.concurrent.PreventDuplicateRequest;
import com.emax.zhenghe.common.concurrent.distributeRedisLock.DistributedLock;
import com.emax.zhenghe.common.enums.AgreementTypeEnum;
import com.emax.zhenghe.common.enums.FileDowloadStatusEnum;
import com.emax.zhenghe.common.enums.PlatformPartnerEnum;
import com.emax.zhenghe.common.enums.ProductEnum;
import com.emax.zhenghe.common.enums.invoice.BillTypeEnum;
import com.emax.zhenghe.common.enums.invoice.InvoiceApplyStatusEnum;
import com.emax.zhenghe.common.enums.invoice.InvoiceBatchAuditStatusEnum;
import com.emax.zhenghe.common.exception.ResponseException;
import com.emax.zhenghe.common.serializer.ExportUtil;
import com.emax.zhenghe.common.system.vo.LoginUser;
import com.emax.zhenghe.common.util.BeanMapper;
import com.emax.zhenghe.common.util.RedisUtil;
import com.emax.zhenghe.common.util.StringUtil;
import com.emax.zhenghe.omsbase.common.aspect.annotation.AutoLog;
import com.emax.zhenghe.omsbase.config.CommonConfig;
import com.emax.zhenghe.omsbase.modules.base.controller.ICustomBaseController;
import com.emax.zhenghe.omsbase.modules.bill.convert.EnterpriseInvoiceApplyVOConverter;
import com.emax.zhenghe.omsbase.modules.bill.service.EnterpriseInvoiceApplyManager;
import com.emax.zhenghe.omsbase.modules.bill.vo.ExcelInvoiceApplyDTO;
import com.emax.zhenghe.rpcapi.modules.bill.dto.EnterpriseInvoiceApplyDTO;
import com.emax.zhenghe.rpcapi.modules.bill.query.EnterpriseInvoiceApplyQuery;
import com.emax.zhenghe.rpcapi.modules.bill.service.EnterpriseInvoiceApplyService;
import com.emax.zhenghe.rpcapi.modules.bill.service.PlatInvoiceAPI;
import com.emax.zhenghe.rpcapi.modules.bill.vo.EnterpriseInvoiceApplyVO;
import com.emax.zhenghe.rpcapi.modules.bill.vo.EnterpriseInvoiceRecordVO;
import com.emax.zhenghe.rpcapi.modules.invoice.service.ElectronicInvoiceService;
import com.emax.zhenghe.rpcapi.modules.invoice.service.EnterpriseInvoiceBatchAuditTaskService;
import com.emax.zhenghe.rpcapi.modules.invoice.service.EnterpriseInvoiceRecordService;
import com.emax.zhenghe.rpcapi.modules.invoice.service.InvoiceManagerService;
import com.emax.zhenghe.rpcapi.modules.invoice.vo.*;
import com.google.common.collect.Lists;
import com.sby.common.export.AsyncExportContext;
import com.sby.common.export.AsyncExportHandler;
import com.sby.common.export.AsyncExportManager;
import com.sby.common.export.AsyncExportState;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.shiro.SecurityUtils;
import org.jeecgframework.poi.excel.ExcelImportUtil;
import org.jeecgframework.poi.excel.entity.ImportParams;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.util.ObjectUtils;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor;

/**
 * 企业开票管理
 */
@Slf4j
@RestController
@RequestMapping("/bill")
public class EnterpriseInvoiceApplyController extends ICustomBaseController<EnterpriseInvoiceApplyVO, EnterpriseInvoiceApplyManager> {

    @DubboReference(providedBy = DubboApps.ZHENGHE_RPCAPI_PROVIDER)
    private EnterpriseInvoiceApplyService invoiceApplyService;

    @DubboReference(providedBy = DubboApps.ZHENGHE_RPCAPI_PROVIDER)
    private InvoiceManagerService invoiceManagerService;

    @DubboReference(providedBy = DubboApps.ZHENGHE_RPCAPI_PROVIDER)
    private ElectronicInvoiceService electronicInvoiceService;


    @DubboReference(providedBy = DubboApps.ZHENGHE_RPCAPI_PROVIDER)
    private EnterpriseInvoiceRecordService enterpriseInvoiceRecordService;

    @DubboReference(providedBy = DubboApps.ZHENGHE_RPCAPI_PROVIDER)
    private EnterpriseInvoiceBatchAuditTaskService enterpriseInvoiceBatchAuditTaskService;

    @DubboReference(providedBy = DubboApps.ZHENGHE_RPCAPI_PROVIDER)
    private EnterpriseAgreementService enterpriseAgreementService;

    @DubboReference(providedBy = DubboApps.ETL_PROVIDER)
    private SysDownloadRecordService sysDownloadRecordService;

    @Autowired
    private CommonConfig commonConfig;

    @Resource
    private EnterpriseInvoiceApplyVOConverter enterpriseInvoiceApplyVOConverter;

    @Autowired
    private RedisUtil redisUtil;

    private static final String BATCH_EXCEL_IMPORT_DELIVER = "BATCH_EXCEL_IMPORT_DELIVER:";

    @Autowired
    private DistributedLock distributedLock;

    private static final String SYSTEM_EXPORT_STR = "_EXPORT_BILL_RECORD_SYSTEM";

    private static final String ARCHIVED_SYSTEM = "_ARCHIVED_SYSTEM";
    @Autowired
    @Qualifier("sysExportTaskExecutor")
    private Executor exportTaskExecutor;

    @Autowired
    private AsyncExportManager asyncExportManager;

    @Resource
    private PlatInvoiceAPI platInvoiceAPI;

    /**
     * 企业开票管理 列表查询,查询全部（运营端）
     *
     * @param invoiceApplyVO
     * @param req
     * @return
     */
    @AutoLog(value = "企业开票管理-列表查询，查询全部（运营端）")
    @ApiOperation(value = "企业开票管理-列表查询", notes = "企业开票管理-列表查询")
    @GetMapping(value = "/list")
    public Result<?> systemList(EnterpriseInvoiceApplyVO invoiceApplyVO, HttpServletRequest req) {
        log.info("企业-开票管理查询请求参数:{}", invoiceApplyVO);
        return invoiceApplyService.list(invoiceApplyVO);
    }

    /**
     * 企业开票管理 分页列表查询
     *
     * @param invoiceApplyVO
     * @param pageNo
     * @param pageSize
     * @return
     */
    @AutoLog(value = "企业开票管理-分页列表查询，查询全部（运营端）")
    @ApiOperation(value = "企业开票管理-分页列表查询", notes = "企业开票管理-分页列表查询")
    @GetMapping(value = "/queryPageList")
    public Result<?> systemQueryPageList(EnterpriseInvoiceApplyVO invoiceApplyVO,
                                         @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
                                         @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize) {
        log.info("企业-开票管理查询请求参数:{}", invoiceApplyVO);
        Result<MyIPage<EnterpriseInvoiceApplyVO>> result = invoiceApplyService.page(invoiceApplyVO, pageNo, pageSize);
        if (result.isSuccess() ) {
            result.getResult().getRecords().forEach(applyVO -> {
                if(PlatformPartnerEnum.LEVY == applyVO.getInvoiceMakerType()){
                    applyVO.setArchived(getAgreementList(applyVO) ? "已归档" : "未归档");
                }
            });
        }
        return result;
    }

    /**
     * 企业开票管理 分页列表服务商发票
     * @param pageNo
     * @param pageSize
     * @return
     */
    @AutoLog(value = "企业开票管理-分页列表服务商发票")
    @ApiOperation(value = "企业开票管理-分页列表服务商发票", notes = "企业开票管理-分页列表服务商发票")
    @GetMapping(value = "/serviceInvoicePage")
    public Result<MyIPage<EnterpriseInvoiceApplyVO>> systemQueryPageList(EnterpriseInvoiceApplyQuery query,
                                         @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
                                         @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize) {
        log.info("企业-开票管理查询请求参数:{}", query);
        query.setInvoiceMakerTypeList(Arrays.asList(PlatformPartnerEnum.LEVY,PlatformPartnerEnum.LIJIANJIN));
        Result<MyIPage<EnterpriseInvoiceApplyDTO>> result = invoiceApplyService.invoicePage(query, pageNo, pageSize);
        MyIPage<EnterpriseInvoiceApplyVO> myIPageResult = result.getResult().convertRecords(enterpriseInvoiceApplyVOConverter::toVO);
        myIPageResult.getRecords().forEach(applyVO -> {
            if(PlatformPartnerEnum.LEVY == applyVO.getInvoiceMakerType()){
                applyVO.setArchived(getAgreementList(applyVO) ? "已归档" : "未归档");
            }
        });
        return Result.success(myIPageResult);
    }

    /**
     * 企业开票管理：
     * 查询本月申请开票金额、已开票金额、未开票金额
     *
     * @param  product 产品线
     * @param  invoiceMakerType 开票方类型
     * @return
     */
    @AutoLog(value = "企业开票管理-查询本月申请开票金额、已开票金额、未开票金额（运营端）")
    @ApiOperation(value = "企业开票管理-查询本月申请开票金额、已开票金额、未开票金额", notes = "企业开票管理-查询本月申请开票金额、已开票金额、未开票金额")
    @GetMapping(value = "/queryBillAmountThisMonth")
    public Result<?> queryBillAmountThisMonth(@RequestParam(name="product",required=false) String product,
                                              @RequestParam(name="invoiceMakerType",required=false) String invoiceMakerType){

        //根据产品线 查询本月申请开票金额、已开票金额、未开票金额，
        //如果产品线product=null 或 product="",则查询所有产品线的
        return invoiceApplyService.queryBillAmountThisMonth(product, invoiceMakerType,null);
    }

    /**
     * 已开票
     *
     * @param invoiceApplyVO
     * @return
     */
    @AutoLog(value = "企业开票管理-已开票")
    @ApiOperation(value="企业开票管理-已开票", notes="企业开票管理-已开票")
    @PutMapping(value = "/billSuccess")
    public Result<?> billSuccess(@RequestBody EnterpriseInvoiceApplyVO invoiceApplyVO) {
        return invoiceApplyService.billSuccess(invoiceApplyVO);
    }

    /**
     * 修改开票状态
     *
     * @param invoiceApplyVO
     * @return
     */
    @AutoLog(value = "企业开票管理-修改开票状态")
    @ApiOperation(value="企业开票管理-修改开票状态", notes="企业开票管理-修改开票状态")
    @PutMapping(value = "/updateStatus")
    public Result<?> updateStatus(@RequestBody EnterpriseInvoiceApplyVO invoiceApplyVO) {
        //获取当前登陆人
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        invoiceApplyVO.setOperatorName(sysUser.getRealname());
        return invoiceApplyService.updateStatus(invoiceApplyVO);
    }

    /**
     * 更新邮寄状态和快递公司信息
     *
     * @param invoiceApplyVO vo
     * @return
     */
    @AutoLog(value = "企业开票管理-更新邮寄状态和快递公司信息")
    @ApiOperation(value="企业开票管理-更新邮寄状态和快递公司信息", notes="企业开票管理-更新邮寄状态和快递公司信息")
    @PutMapping(value = "/updateDelivered")
    public Result<?> delivered(@RequestBody EnterpriseInvoiceApplyVO invoiceApplyVO) {
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        invoiceApplyVO.setOperatorName(sysUser.getRealname());
        return invoiceApplyService.updateDelivered(invoiceApplyVO);
    }

    /**
     * 编辑
     *
     * @param invoiceApplyVO
     * @return
     */
    @AutoLog(value = "企业开票管理-编辑")
    @ApiOperation(value="企业开票管理-编辑", notes="企业开票管理-编辑")
    @PutMapping(value = "/edit")
    public Result<?> edit(@RequestBody EnterpriseInvoiceApplyVO invoiceApplyVO) {
        invoiceApplyService.updateById(invoiceApplyVO);
        return Result.successWithMsg("编辑成功!");
    }


    /**
     * 通过id删除
     *
     * @param id
     * @return
     */
    @AutoLog(value = "企业开票管理-通过id删除")
    @ApiOperation(value="企业开票管理-通过id删除", notes="企业开票管理-通过id删除")
    @DeleteMapping(value = "/delete")
    public Result<?> delete(@RequestParam(name="id",required=true) String id) {
        invoiceApplyService.removeById(id);
        return Result.successWithMsg("删除成功!");
    }

    /**
     * 批量删除
     *
     * @param ids
     * @return
     */
    @AutoLog(value = "企业开票管理-批量删除")
    @ApiOperation(value="企业开票管理-批量删除", notes="企业开票管理-批量删除")
    @DeleteMapping(value = "/deleteBatch")
    public Result<?> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
        invoiceApplyService.removeByIds(Arrays.asList(ids.split(",")));
        return Result.successWithMsg("批量删除成功！");
    }

    /**
     * 通过id查询
     *
     * @param id
     * @return
     */
    @AutoLog(value = "企业开票管理-通过id查询")
    @ApiOperation(value="企业开票管理-通过id查询", notes="企业开票管理-通过id查询")
    @GetMapping(value = "/queryById")
    public Result<?> queryById(@RequestParam(name="id",required=true) String id) {
        EnterpriseInvoiceApplyVO bill = invoiceApplyService.getById(id);
        return Result.success(bill);
    }

    /**
     * 通过billNo查询
     *
     * @param billNo
     * @return
     */
    @AutoLog(value = "企业开票管理-根据billNo查询详情")
    @ApiOperation(value="企业开票管理-根据billNo查询详情", notes="企业开票管理-根据billNo查询详情")
    @GetMapping(value = "/queryByBillNo")
    public Result<?> queryBillDetailByBillNo(@RequestParam(name="billNo",required=true) String billNo) {
        return invoiceApplyService.queryBillDetailByBillNo(Long.parseLong(billNo));
    }

    /**
     * 导出excel
     *
     * @param invoiceApplyVO
     */
    @AutoLog(value = "企业开票管理-导出excel")
    @RequestMapping(value = "/exportXls")
    public Result<Void> exportXls(EnterpriseInvoiceApplyVO invoiceApplyVO) {
        log.info("企业开票管理-导出,导出条件={}", JSON.toJSONString(invoiceApplyVO));
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        //从第一页开始查询
        int pageNo = 1;
        //每页最多显示2000行数据
        int pageSize = 4000;
        //调用分页查询接口，先查出第一页的数据,总数据条数,总页数
        Result<MyIPage<EnterpriseInvoiceApplyVO>> result = invoiceApplyService.page(invoiceApplyVO, pageNo, pageSize);
        if (result == null || !result.isSuccess() || result.getResult() == null) {
            throw new ResponseException("导出异常，请重新尝试");
        }
        //获取总数据条数
        Long totalRecordsCount =  result.getResult().getTotal();

        AsyncExportState state = asyncExportManager.submit((new AsyncExportHandler<ExcelInvoiceApplyDTO>() {
            @Override
            public List<ExcelInvoiceApplyDTO> moreData(AsyncExportContext asyncExportContext) {
                Result<MyIPage<EnterpriseInvoiceApplyVO>> myIPageResult = invoiceApplyService.page(invoiceApplyVO, asyncExportContext.getCurrPage().get(), pageSize);
                //数据处理
                asyncExportContext.setReportUrl(commonConfig.reportUrl);
                asyncExportContext.setPages((int) myIPageResult.getResult().getPages());
                List<ExcelInvoiceApplyDTO> totalDownloadDTOList = new ArrayList<>();
                buildInvoiceApplyExcelVO(myIPageResult.getResult().getRecords(), totalDownloadDTOList);
                asyncExportContext.getCurrPage().getAndIncrement();
                return totalDownloadDTOList;
            }
        }));
        //组装数据
        SysDownloadRecordDTO dto = new SysDownloadRecordDTO();
        dto.setStatus(FileDowloadStatusEnum.FILE_WAIT);
        dto.setId(state.getId());
        dto.setCreateBy(sysUser.getUsername());
        dto.setIfDelete(1);
        dto.setOperation("导出");
        dto.setOperationTotalCount(String.valueOf(totalRecordsCount));
        dto.setSysMenu("票据中心");
        dto.setSysName(ProductEnum.OMS.getDescription());
        dto.setSysModule("发票列表");
        dto.setSysType(ProductEnum.OMS.getCode());
        sysDownloadRecordService.save(dto);//保存下载记录
        return ResultX.successWithMsg("导出成功，请去报表中心/下载管理页面查看数据");


    }

    /**
     * 导出excel
     * @param query
     */
    @AutoLog(value = "企业开票管理-导出excel")
    @RequestMapping(value = "/serviceInvoiceExportXls")
    public Result<Void> serviceInvoiceExportXls(EnterpriseInvoiceApplyQuery query) {
        query.setInvoiceMakerTypeList(Arrays.asList(PlatformPartnerEnum.LEVY,PlatformPartnerEnum.LIJIANJIN));
        log.info("企业开票管理-导出,导出条件={}", JSON.toJSONString(query));
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        //从第一页开始查询
        int pageNo = 1;
        //每页最多显示2000行数据
        int pageSize = 4000;
        //调用分页查询接口，先查出第一页的数据,总数据条数,总页数
        Result<MyIPage<EnterpriseInvoiceApplyDTO>> result = invoiceApplyService.invoicePage(query, pageNo, pageSize);
        if (result == null || !result.isSuccess() || result.getResult() == null) {
            throw new ResponseException("导出异常，请重新尝试");
        }
        //获取总数据条数
        Long totalRecordsCount =  result.getResult().getTotal();

        AsyncExportState state = asyncExportManager.submit((new AsyncExportHandler<ExcelInvoiceApplyDTO>() {
            @Override
            public List<ExcelInvoiceApplyDTO> moreData(AsyncExportContext asyncExportContext) {
                Result<MyIPage<EnterpriseInvoiceApplyDTO>> myIPageResult = invoiceApplyService.invoicePage(query, asyncExportContext.getCurrPage().get(), pageSize);
                //数据处理
                asyncExportContext.setReportUrl(commonConfig.reportUrl);
                asyncExportContext.setPages((int) myIPageResult.getResult().getPages());
                List<ExcelInvoiceApplyDTO> totalDownloadDTOList = new ArrayList<>();
                buildInvoiceApplyExcelVO(enterpriseInvoiceApplyVOConverter.toVO(myIPageResult.getResult().getRecords()), totalDownloadDTOList);
                asyncExportContext.getCurrPage().getAndIncrement();
                return totalDownloadDTOList;
            }
        }));
        //组装数据
        SysDownloadRecordDTO dto = new SysDownloadRecordDTO();
        dto.setStatus(FileDowloadStatusEnum.FILE_WAIT);
        dto.setId(state.getId());
        dto.setCreateBy(sysUser.getUsername());
        dto.setIfDelete(1);
        dto.setOperation("导出");
        dto.setOperationTotalCount(String.valueOf(totalRecordsCount));
        dto.setSysMenu("票据中心");
        dto.setSysName(ProductEnum.OMS.getDescription());
        dto.setSysModule("发票列表");
        dto.setSysType(ProductEnum.OMS.getCode());
        sysDownloadRecordService.save(dto);//保存下载记录
        return ResultX.successWithMsg("导出成功，请去报表中心/下载管理页面查看数据");


    }



    //设置归档状态
    private void buildInvoiceApplyExcelVO(List<EnterpriseInvoiceApplyVO> allRecordList, List<ExcelInvoiceApplyDTO> totalDownloadDTOList) {
        allRecordList.forEach(applyVO -> {
            ExcelInvoiceApplyDTO vo = BeanMapper.map(applyVO, ExcelInvoiceApplyDTO.class);
            if(PlatformPartnerEnum.LEVY == applyVO.getInvoiceMakerType()){
                vo.setArchived(getAgreementList(applyVO) ? "已归档" : "未归档");
            }
            if(StringUtils.isNotEmpty(vo.getInvoiceType())){
                vo.setInvoiceType(BillTypeEnum.getValueByCode(vo.getInvoiceType()));
            }
            if(StringUtils.isNotEmpty(vo.getBillStatus())){
                vo.setBillStatus(InvoiceApplyStatusEnum.getValueByCode(vo.getBillStatus()));
            }
            totalDownloadDTOList.add(vo);
        });
    }

    //调渠道返回的协议信息，启用缓存支持
    private boolean getAgreementList(EnterpriseInvoiceApplyVO applyVO) {
        //缓存规则，如：_ARCHIVED_SYSTEM+企业ID+服务商ID
        String cacheKey = ARCHIVED_SYSTEM.concat(String.valueOf(applyVO.getEnterpriseId())).concat(String.valueOf(applyVO.getInvoiceMakerId()));

        Object object = redisUtil.get(cacheKey);
        if(ObjectUtil.isNotNull(object)){
            log.info("发票列表导出，直接获取到数据[{}]", object);
            return (boolean) object;
        }else {
            log.info("发票列表导出，RPC调用获取到数据");
            EnterpriseAgreementVo agreementVo = new EnterpriseAgreementVo();
            agreementVo.setEnterpriseId(applyVO.getEnterpriseId());
            agreementVo.setServiceId(applyVO.getInvoiceMakerId());
            agreementVo.setAgreementType(AgreementTypeEnum.SERVICE_PROVIDER.getCode());
            ResultX<List<EntAgreementResponseDTO>> resultX = enterpriseAgreementService.getEnterpriseAgreementChangeServiceId(agreementVo);
            log.info("发票列表导出，RPC调用获取到数据[{}]", JSON.toJSONString(resultX));
            if (resultX != null && resultX.isSuccess() && resultX.getResult() != null) {
                List<EntAgreementResponseDTO> dtoList = resultX.getResult();
                if (CollectionUtils.isEmpty(dtoList)) {
                    redisUtil.set(cacheKey, false, 500);
                    return false;
                }
                final Boolean archived = dtoList.get(0).getArchived();
                if(archived != null && archived){
                    redisUtil.set(cacheKey, true, 7 * 3600L);
                    return true;
                }
            }
            redisUtil.set(cacheKey, false, 500);
            return false;

        }


    }


    /**
     * 通过excel导入数据
     *
     * @param request
     * @param response
     * @return
     */
    @AutoLog(value = "企业开票管理-通过excel导入数据")
    @RequestMapping(value = "/importExcel", method = RequestMethod.POST)
    public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
        return super.importExcel(request, response, EnterpriseInvoiceApplyVO.class);
    }


    @ApiOperation(value="发票管理-电票获取服务商开票方列表", notes="发票管理-电票获取服务商开票方列表")
    @PostMapping(value = "/resendEleInvoiceToEmail")
    public Result<Void> resendEleInvoiceToEmail(@RequestBody InvoiceToEmailVo vo){
        return electronicInvoiceService.resendEleInvoiceToEmail(vo);
    }


    @ApiOperation(value="发票管理-电票蓝票开票中状态电票查询功能", notes="发票管理-电票蓝票开票中状态电票查询功能")
    @GetMapping(value = "/getEleInvoiceReq")
    public Result<Void> getEleInvoiceReq(String billNo){
        return electronicInvoiceService.getEleInvoiceReq(billNo, 0);
    }


    @ApiOperation(value="发票管理-电票开票失败的重新开票功能", notes="发票管理-电票开票失败的重新开票功能")
    @GetMapping(value = "/rePushEleInvoiceReq")
    public Result<Void> rePushEleInvoiceReq(String billNo){
        return electronicInvoiceService.rePushEleInvoiceReq(billNo);
    }


    @ApiOperation(value="发票管理-发票作废", notes="发票管理-发票作废")
    @PutMapping(value = "/failInvoice")
    public Result<Void> failInvoice(@RequestBody EnterpriseInvoiceApplyVO vo){
        //获取当前登陆人
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        vo.setOperatorName(sysUser.getRealname());
        return  invoiceApplyService.failInvoice(vo);
    }

    /**
     * 通过excel批量导入快递信息
     * @param request
     * @param response
     * @return
     */
    @ApiOperation(value="发票管理-批量导入快递信息", notes="发票管理-批量导入快递信息")
    @PostMapping(value = "/import/deliveryExcel")
    public Result<DeliveryExcelModelRes> importDeliveryExcel(HttpServletRequest request, HttpServletResponse response) {

        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();

        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
        Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
        for (Map.Entry<String, MultipartFile> entity : fileMap.entrySet()) {
            MultipartFile file = entity.getValue();// 获取上传文件对象
            ImportParams params = new ImportParams();
            //表格标题所在行，计数从0开始
            params.setTitleRows(0);
            //表格sheet数量
            params.setSheetNum(1);

            try {
                List<DeliveryExcelModelVO> list = ExcelImportUtil.importExcel(file.getInputStream(), DeliveryExcelModelVO.class, params);
                if(CollectionUtils.isEmpty(list)){
                    return Result.error("获取数据为空，请检查上传文档是否标准");
                }
                Result<DeliveryExcelModelRes> res = invoiceManagerService.batchImportDeliveryExcel(list, sysUser.getRealname());
                if(!ObjectUtils.isEmpty(res) && res.isSuccess() && !ObjectUtils.isEmpty(res.getResult())){
                    DeliveryExcelModelRes result = res.getResult();
                    List<DeliveryExcelModelVO> errorList = result.getErrorList();
                    if(!CollectionUtils.isEmpty(errorList)){
                        String uuid = String.valueOf(IdWorker.getId());
                        redisUtil.set(BATCH_EXCEL_IMPORT_DELIVER.concat(uuid), JSON.toJSONString(errorList), 60 * 30);
                        result.setUuid(uuid);
                    }
                    return res;
                }
                return Result.error("上传处理失败，请稍后尝试");
            } catch (Exception e) {
                log.error(e.getMessage(),e);
            } finally {
                try {
                    file.getInputStream().close();
                } catch (IOException e) {
                    log.error(e.getMessage(), e);
                }
            }
        }
        return Result.error("上传处理失败，请稍后尝试");
    }


    /**
     * 通过excel导出错误得快递数据
     * @return
     */
    @ApiOperation(value="发票管理-导出错误的快递数据", notes="发票管理-导出错误的快递数据")
    @GetMapping(value = "/export/deliveryExcel")
    public ModelAndView exportDeliveryExcel(HttpServletRequest request, String uuid) {

       Object o = redisUtil.get(BATCH_EXCEL_IMPORT_DELIVER.concat(uuid));

       List<DeliveryExcelModelVO> list = new ArrayList<>();
       if(!ObjectUtils.isEmpty(o)){
           list = JSON.parseArray(o.toString(),DeliveryExcelModelVO.class);
       }

        return ExportUtil.exportXls(request, list, DeliveryExcelModelVO.class, "错误数据列表");
    }

    /**
     * 平台开票管理-开票记录
     * @return
     */
    @ApiOperation(value="平台开票管理-开票记录", notes="平台开票管理-开票记录")
    @GetMapping(value = "/recordList")

    public Result<List<EnterpriseInvoiceRecordVO>> recordList(String billNo) {
        return enterpriseInvoiceRecordService.list(billNo);
    }


    /**
     * 平台开票管理-开票记录
     * @return
     */
    @AutoLog(value = "平台开票管理-批量上传")
    @ApiOperation(value="平台开票管理-批量上传", notes="平台开票管理-批量上传")
    @PostMapping(value = "/batchSave")
    public Result<Void> save(InvoiceBatchAuditTaskVO invoiceBatchAuditTaskVO) {
        log.info("平台开票管理-开票记录:{}", invoiceBatchAuditTaskVO);

        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        invoiceBatchAuditTaskVO.setOperatorName(sysUser.getRealname());
        invoiceBatchAuditTaskVO.setAuditStatus(InvoiceBatchAuditStatusEnum.DOING.getCode());
        return enterpriseInvoiceBatchAuditTaskService.save(invoiceBatchAuditTaskVO);
    }


    /**
     * 企业开票管理 批量审核记录
     *
     * @param invoiceBatchAuditTaskVO
     * @param pageNo
     * @param pageSize
     * @param req
     * @return
     */
    @AutoLog(value = "企业开票管理-批量审核记录")
    @ApiOperation(value = "企业开票管理-批量审核记录", notes = "企业开票管理-批量审核记录")
    @GetMapping(value = "/queryBatchPageList")
    public Result<MyIPage<InvoiceBatchAuditTaskVO>> queryBatchPageList(InvoiceBatchAuditTaskVO invoiceBatchAuditTaskVO,
                                                                     @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
                                                                     @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
                                                                     HttpServletRequest req) {
        log.info("企业开票管理-批量审核记录:{}", invoiceBatchAuditTaskVO);
        return enterpriseInvoiceBatchAuditTaskService.page(invoiceBatchAuditTaskVO,pageNo,pageSize);
    }


    /**
     * 企业开票管理 批量审核记录
     *
     * @param auditTaskNo
     * @param req
     * @return
     */
    @AutoLog(value = "企业开票管理-批量审核下载失败明细")
    @ApiOperation(value = "企业开票管理-批量审核下载失败明细", notes = "企业开票管理-批量审核下载失败明细")
    @RequestMapping(value = "/batchExportXls")
    public ModelAndView batchExportXls(String auditTaskNo, HttpServletRequest req) {
        log.info("企业开票管理-批量审核记录:{}", auditTaskNo);
        final Result<InvoiceBatchAuditTaskVO> oneById = enterpriseInvoiceBatchAuditTaskService.findOneById(
            auditTaskNo);
        if(!oneById.isSuccess() && oneById.getResult() == null){
            return null;
        }
        final String errorData = oneById.getResult().getErrorData();
        final List<InvoiceBatchAuditExcelExportVO> excelExportVOS = JSON.parseArray(errorData, InvoiceBatchAuditExcelExportVO.class);
        return ExportUtil.exportXls(req, excelExportVOS, InvoiceBatchAuditExcelExportVO.class, "错误文件");
    }

    /**
     * 服务商发票管理 主动查询服务商发票信息
     * @param billNo
     * @return
     */
    @AutoLog(value = "票据中心-服务商发票管理-主动查询服务商发票信息并更新数据")
    @ApiOperation(value="票据中心-服务商发票管理-主动查询服务商发票信息并更新数据", notes="票据中心-服务商发票管理-主动查询服务商发票信息并更新数据")
    @GetMapping(value = "/findBillInfoFromLevy")
    public Result<String> findBillInfoFromLevy(String billNo){
        try {
            String cacheKey = "findBillInfoFromLevy" + billNo;
            if (redisUtil.hasKey(cacheKey)) {
                return Result.successWithMsg("系统正在加载发票附件，请勿重复点击");
            }
            redisUtil.set(cacheKey, billNo, 5L);
            invoiceManagerService.updateInvoiceInfoFromLevy(billNo);
            return Result.success();
        }catch (Exception e){
            log.error("###/findInvoiceInfoFromLevy 主动查询服务商发票信息并更新数据:", e);
            return Result.error("主动查询服务商发票信息失败");
        }
    }

    /**
     * 票据中心-平台管理费-平台开票管理 批量确认
     * @return
     */
    @AutoLog(value = "票据中心-平台管理费-平台开票管理-电票批量确认")
    @ApiOperation(value="票据中心-平台管理费-平台开票管理-电票批量确认", notes="票据中心-平台管理费-平台开票管理-电票批量确认")
    @GetMapping(value = "/platEleInvoiceBatchConfirm")
    @PreventDuplicateRequest(key = "platEleInvoiceBatchConfirm", expireSeconds = 5, autoReleaseLock = true)
    public Result<Void> platEleInvoiceBatchConfirm(EnterpriseInvoiceApplyVO invoiceApplyVO){
        log.info("平台管理费电票批量确认，入参：{}", JSON.toJSONString(invoiceApplyVO));
        try {
            if (StringUtil.isEmpty(invoiceApplyVO.getProduct())) {
                invoiceApplyVO.setProductList(Lists.newArrayList(ProductEnum.BossKG.getCode(), ProductEnum.INDUSTRY_DESIGN.getCode()));
            }
            return platInvoiceAPI.eleInvoiceBatchConfirm(invoiceApplyVO);
        }catch (Exception e){
            log.error("###/平台电票批量确认发生异常:", e);
            return Result.error("平台电票批量确认失败");
        }
    }

    /**
     * 票据中心-平台管理费-平台开票管理 单票确认
     * @return
     */
    @AutoLog(value = "票据中心-平台管理费-平台开票管理-电票单票确认")
    @ApiOperation(value="票据中心-平台管理费-平台开票管理-电票单票确认", notes="票据中心-平台管理费-平台开票管理-电票单票确认")
    @GetMapping(value = "/platEleInvoiceSingleConfirm")
    @PreventDuplicateRequest(key = "platEleInvoiceSingleConfirm", spEL = "#billNo", expireSeconds = 5, autoReleaseLock = true)
    public Result<Void> platEleInvoiceSingleConfirm(String billNo){
        try {
            if (StringUtil.isEmpty(billNo)) {
                return Result.error("确认失败，请求参数为空");
            }
            log.info("平台电票单票确认，请求入参：{}", billNo);
            ResultX<Void> confirmResult = platInvoiceAPI.eleInvoiceSingleConfirm(Long.parseLong(billNo));
            log.info("平台电票单票确认，返回结果：{}", JSON.toJSONString(confirmResult));
            return confirmResult;
        }catch (Exception e){
            log.error("###/平台电票单票确认发生异常:", e);
            return Result.error("平台电票单票确认失败");
        }
    }
}
